using System;
using System.Text;
using System.Net;
using System.IO;
using System.Xml;
using System.Globalization;
using System.Xml.XPath;

namespace MIS.EN.WebDav
{
    /// <summary>
    /// This class contains some common calls for WebDAV based on the WebDAV protocol.
    /// </summary>
    public class WebDavCommand
    {
        public enum WebDavMethod
        {
            Search,
            PropPatch,
            Delete
        }

        private NetworkCredential credentials;
        private bool useFormsBasedAuthentication;
        private bool useIsaServer2006;
        private FormsBasedAuthentication authHelper;
        private bool usesHexadecimalXmlNames;

        public WebDavCommand(NetworkCredential credentials, bool useFormsBasedAuthentication, 
            bool useIsaServer2006, bool usesHexadecimalXmlNames)
        {
            this.credentials = credentials;
            this.useFormsBasedAuthentication = useFormsBasedAuthentication;
            this.useIsaServer2006 = useIsaServer2006;
            this.usesHexadecimalXmlNames = usesHexadecimalXmlNames;
            if (this.useFormsBasedAuthentication)
            {
                this.authHelper = new FormsBasedAuthentication();
            }
        }

        public int ExecuteNonQuery(Uri requestUri, WebDavMethod method, string xmlMessage)
        {
            int status = 0;
            using (HttpWebResponse response = this.GetWebDavResponse(requestUri, method, xmlMessage))
            {
                status = (int) response.StatusCode;
            }
            return status;
        }

        public XmlDocument ExecuteXmlDocument(Uri requestUri, WebDavMethod method, string xmlMessage)
        {
            XmlDocument responseXml = new XmlDocument();
            if (this.usesHexadecimalXmlNames)
            {
                using (HttpWebResponse response = this.GetWebDavResponse(requestUri, method, xmlMessage))
                {
                    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                    {
                        string responseRawData = reader.ReadToEnd();
                        responseRawData = responseRawData.Replace("0x", "x");
                        responseXml.LoadXml(responseRawData);
                    }
                }
            }
            else
            {
                using (XmlReader reader = this.ExecuteXmlReader(requestUri, method, xmlMessage))
                {
                    if (reader != null)
                    {
                        responseXml.Load(reader);
                    }
                }
            }
            return responseXml;
        }

        public XmlReader ExecuteXmlReader(Uri requestUri, WebDavMethod method, string xmlMessage)
        {
            HttpWebResponse response = this.GetWebDavResponse(requestUri, method, xmlMessage);
            return new XmlTextReader(response.GetResponseStream());
        }

        private HttpWebResponse GetWebDavResponse(Uri requestUri, WebDavMethod method, string xmlMessage)
        {
            // Set up the request to accept all server certificates
            ServicePointManager.CertificatePolicy = new TrustedCertificatePolicy();

            // Create the request
            HttpWebRequest davRequest = WebRequest.Create(requestUri) as HttpWebRequest;

            // Set the credentials
            davRequest.Credentials = this.credentials;

            // Set the headers
            davRequest.KeepAlive = false;
            davRequest.Headers.Set("Pragma", "no-cache");

            // This is supposed to speed up the query
            davRequest.ServicePoint.Expect100Continue = false;
            davRequest.ServicePoint.UseNagleAlgorithm = false;
                        
            // Set the request default timeout to 1 minute
            davRequest.Timeout = 60000;
            davRequest.Method = method.ToString().ToUpper(CultureInfo.CurrentCulture);

            // Set the content type for text/xml
            davRequest.ContentType = "text/xml";

            // If using OWA forms-based authentication, then authenticate and add the cookies 
            // from the authentication to the WebDAV request
            if (this.useFormsBasedAuthentication)
            {
                davRequest.CookieContainer = authHelper.GetOwaCookies(requestUri.Host,
                    requestUri.Scheme, this.credentials, this.useIsaServer2006);
            }

            // Write the xml message to the request stream
            if (xmlMessage != null && xmlMessage.Length > 0)
            {
                // Encode the body using UTF-8
                byte[] byteBody = ASCIIEncoding.ASCII.GetBytes(xmlMessage);
                if (byteBody != null)
                {
                    // Set the content length of the string being posted
                    davRequest.ContentLength = byteBody.Length;

                    // Write the bytes to the request stream
                    using (Stream requestStream = davRequest.GetRequestStream())
                    {
                        requestStream.Write(byteBody, 0, byteBody.Length);
                    }
                }
            }

            // Send the request and get the response
            return davRequest.GetResponse() as HttpWebResponse;
        }
    }
}
